package com.ylsk.common.utils;

import com.ylsk.common.exception.ServiceException;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * MinioUtil
 * @author JWB
 * @date 2023/9/4
 */
@Slf4j
@Component
public class MinioUtil {

    @Autowired
    private MinioClient client;


    /**
     * 校验bucket
     */
    public boolean checkBucket(String bucketName) {
        try {
            return client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            log.error("MINIO校验BUCKET ==> 校验BUCKET失败！", e);
            return false;
        }
    }

    /**
     * 上传文件
     */
    public void uploadFile(MultipartFile file, String bucketName, String filePath) {
        //判断文件是否为空
        if (null == file || file.getSize() == 0) {
            throw new ServiceException("文件为空！");
        }
        //判断存储桶是否存在
        if (!checkBucket(bucketName)) {
            throw new ServiceException("文件存储桶不存在！");
        }
        try {
            //开始上传
            @Cleanup
            InputStream inputStream = file.getInputStream();
            client.putObject(PutObjectArgs.builder().bucket(bucketName).object(filePath).stream(inputStream, file.getSize(), -1).contentType(file.getContentType()).build());
        } catch (Exception e) {
            log.error("MINIO上传文件 ==> 上传失败！", e);
            throw new ServiceException("上传失败！");
        }
    }

    /**
     * 获取全部bucket
     */
    public List<Bucket> getBuckets() {
        try {
            return client.listBuckets();
        } catch (Exception e) {
            log.error("MINIO获取全部BUCKET ==> 获取失败！", e);
            throw new ServiceException("获取失败！");
        }
    }

    /**
     * 根据bucketName获取信息
     */
    public Bucket getBucket(String bucketName) {
        try {
            Bucket bucket = null;
            Optional<Bucket> first = client.listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
            if (first.isPresent()) {
                bucket = first.get();
            }
            return bucket;
        } catch (Exception e) {
            log.error("MINIO获取信息 ==> 获取信息失败！", e);
            throw new ServiceException("获取信息失败！");
        }
    }

    /**
     * 根据bucketName删除信息
     */
    public void removeBucket(String bucketName) {
        try {
            client.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
            log.info("MINIO删除BUCKET ==> 删除BUCKET成功！");
        } catch (Exception e) {
            log.error("MINIO删除BUCKET ==> 删除BUCKET失败！", e);
            throw new ServiceException("删除BUCKET失败！");
        }
    }

    /**
     * 获取文件外链
     * @param bucketName bucket名称
     * @param filePath 文件名称
     * @param expires 过期时间 <=7
     * @return url
     */
    public String getFileUrl(String bucketName, String filePath, Integer expires) {
        try {
            return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(filePath).expiry(expires, TimeUnit.HOURS).build());
        } catch (Exception e) {
            log.error("MINIO获取文件外链 ==> 获取文件外链失败！", e);
            throw new ServiceException("获取文件外链失败！");
        }
    }

    public String getFileUrl(String bucketName, String filePath) {
        try {
            return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(filePath).build());
        } catch (Exception e) {
            log.error("MINIO获取文件外链 ==> 获取文件外链失败！", e);
            throw new ServiceException("获取文件外链失败！");
        }
    }
    /**
     * 获取文件
     * @param bucketName bucket名称
     * @param filePath 文件名称
     * @return ⼆进制流
     */
    public InputStream getFile(String bucketName, String filePath) {
        try {
            return client.getObject(GetObjectArgs.builder().bucket(bucketName).object(filePath).build());
        } catch (Exception e) {
            log.error("MINIO获取文件 ==> 获取文件失败！", e);
            throw new ServiceException("获取文件失败！");
        }
    }

    /**
     * 下载文件
     * @param bucketName bucket名称
     * @param filePath 文件路径
     * @param fileName 文件名称
     */
    public void downloadFile(String bucketName, String filePath, String fileName) {
        try {
            client.downloadObject(DownloadObjectArgs.builder().bucket(bucketName).object(filePath).filename(fileName).build());
        } catch (Exception e) {
            log.error("MINIO获取文件 ==> 下载文件失败！", e);
            throw new ServiceException("下载文件失败！");
        }
    }

    /**
     * 获取文件信息和对象的元数据
     * @param bucketName bucket名称
     * @param filePath 文件名称
     */
    public StatObjectResponse getFileInfo(String bucketName, String filePath) {
        try {
            return client.statObject(StatObjectArgs.builder().bucket(bucketName).object(filePath).build());
        } catch (Exception e) {
            log.error("MINIO获取文件信息 ==> 获取文件信息失败！", e);
            throw new ServiceException("获取文件信息失败！");
        }
    }

    /**
     * 删除文件（单个）
     * @param bucketName bucket名称
     * @param filePath 文件名称
     */
    public void removeFile(String bucketName, String filePath) {
        try {
            client.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(filePath).build());
            log.info("MINIO删除文件 ==> 删除文件成功！");
        } catch (Exception e) {
            log.error("MINIO删除文件 ==> 删除文件失败！", e);
            throw new ServiceException("删除文件失败！");
        }
    }


}
